
#ifndef __TILED_TMXPARSER_H__
#define __TILED_TMXPARSER_H__

#include "math/CCGeometry.h"
#include "platform/CCSAXParser.h"
#include "base/CCVector.h"
#include "base/CCValue.h"
#include <string>
#include "base/CCRef.h"
#include "TiledDefs.h"
#include "2d/CCSpriteFrame.h"

USING_NS_CC;

namespace Tiled {

	/** Possible orientations of the TMX map */
	enum
	{
		/** Orthogonal orientation */
		TmxOrientationOrtho,

		/** Hexagonal orientation */
		TmxOrientationHex,

		/** Isometric orientation */
		TmxOrientationIso,

		/** Isometric staggered orientation*/
		TmxOrientationStaggered,
	};

	class TmxLayerInfo;
	class TmxMapInfo;

	class TmxLayerInfo : public LayerData
	{
	public:

		TmxLayerInfo();
		virtual ~TmxLayerInfo();

		Size                size;
		uint32_t*			tiles;
		Vec2				offset;

		bool isValid(int x, int y) const {
			return x < size.width && x >= 0 && y < size.height && y >= 0;
		}

		int getGid(int x, int y) const {
			return tiles[y * (int)size.width + x];
		}

		virtual bool load(const tinyxml2::XMLElement* element);
	};

	enum TmxObjectType
	{
		/// Rectangle.
		OT_RECTANGLE = 0,
		/// Ellipse.
		OT_ELLIPSE,
		/// Polygon.
		OT_POLYGON,
		/// Polyline.
		OT_POLYLINE,
		/// Tile.
		OT_TILE,
		/// Invalid.
		OT_INVALID = 0xffff
	};

	/// Tile map object.
	class TmxMapObject : public Ref
	{
	public:
		TmxMapObject();

		/// Return type.
		TmxObjectType GetObjectType() const { return _objectType; }
		/// Return name.
		std::string GetName() const { return _name; }
		/// Return type.
		std::string GetType() const { return _type; }
		/// Return position.
		const Vec2& GetPosition() const { return _position; }
		/// Return size (for rectangle and ellipse).
		const Size& GetSize() const { return _size; }
		/// Return number of points (use for script).
		unsigned GetNumPoints() const;
		/// Return point at index (use for script).
		const Vec2& GetPoint(unsigned index) const;
		/// Return tile Gid.
		int GetTileGid() const { return _gid; }

	private:

		/// Object type.
		TmxObjectType _objectType;
		/// Name.
		std::string _name;
		/// Type.
		std::string _type;
		/// Position.
		Vec2 _position;
		/// Size (for rectangle and ellipse).
		Size _size;
		/// Points(for polygon and polyline).
		Vector<Vec2> _points;
		/// Gid (for tile).
		int _gid;

		PropertySet _properties;
	};


	class TmxObjectGroup : public LayerData
	{
	public:
		TmxObjectGroup();

		/// Load from XML element.
		void Load(const tinyxml2::XMLElement* element, const TmxMapInfo& info);
		/// Return number of objects.
		unsigned GetNumObjects() const { return _objects.size(); }
		/// Return tile map object at index.
		TmxMapObject* GetObject(unsigned index) const;

	private:
		/// Objects.
		Vector<TmxMapObject*> _objects;
	};

	class TmxMapInfo : public Ref
	{
	public:
		TmxMapInfo();
		virtual ~TmxMapInfo();

		bool init(const char* tmxString, size_t size, const char* resourcePath);

		/// map orientation
		inline int getOrientation() const { return _orientation; };
		inline void setOrientation(int orientation) { _orientation = orientation; };

		/// map width & height
		inline const Size& getMapSize() const { return _mapSize; };
		inline void setMapSize(const Size& mapSize) { _mapSize = mapSize; };

		/// tiles width & height
		inline const Size& getTileSize() const { return _tileSize; };
		inline void setTileSize(const Size& tileSize) { _tileSize = tileSize; };

		/// Layers
		TmxLayerInfo* getLayer(const std::string& name) const;
		inline Vector<TmxLayerInfo*>& getLayers() { return _layers; };

		SpriteFrame* getTile(int gid) {
			return _gidToTile[gid];
		}

		cocos2d::Vec2 posToTileIndex(float x, float y);
		cocos2d::Vec2 tileIndexToPos(int x, int y);
	protected:
		bool parseXMLString(const char* data, size_t size);

		void loadTileSet(const tinyxml2::XMLElement* element);
		void loadTileSetXml(const tinyxml2::XMLElement* element, int firstgid);
		void loadLayer(const tinyxml2::XMLElement* element);
		void loadObject(TmxObjectGroup* group, const tinyxml2::XMLElement* element);
		void loadObjectGroup(const tinyxml2::XMLElement* element);
		/// map orientation
		int _orientation;
		/// map width & height
		Size _mapSize;
		/// tiles width & height
		Size _tileSize;
		/// Layers
		Vector<TmxLayerInfo*> _layers;
		/// ObjectGroups
		Vector<TmxObjectGroup*> _objectGroups;
		/// properties
		PropertySet _properties;

		std::string _path;
		std::map<int, PropertySet> _gidToProperty;
		std::map<int, SpriteFrame*> _gidToTile;
	};

	// end of tilemap_parallax_nodes group
	/// @}

}

#endif//__TILED_TMXPARSER_H__

